/*
  Flutter-Dart异步和网络请求
  https://blog.csdn.net/a1204942755/article/details/124478317



  1.Dart异步
  1.1 Dart单线程
  Dart是单线程的，不支持多线程。
  Dart实现异步是使用的单线程+循环调用的方式
  类似于网络请求、文件读写的IO操作，都可以基于非阻塞调用

  阻塞式调用和非阻塞式调用
  阻塞和非阻塞关注的是程序在等待调用结果（消息、返回值）时的状态
  阻塞式调用： 调用结果返回之前，当前线程会被挂起，调用线程只有在得到调用结果之后才会继续执行
  非阻塞式调用： 调用执行后，当前线程不会停止执行，只需要过一段时间来检查一下有没有结果返回即可

  1.2 Dart事件循环
  什么是事件循环
  单线程模型中主要就是在维护着一个事件循环（Event Loop）
  事件循环是什么：
  1.将需要处理的一系列事件（包括点击事件、IO事件、网络事件）放在一个事件队列（Event Queue）中。
  2.不断的从时间队列（Event Queue）中取出事件，并执行其对应需要执行的代码块，直到时间队列清空位置

  1.3 Dart异步操作
  Dart中的异步操作主要使用Future以及async、await

 */
import 'dart:io';

void main() {
  print('main start');

/*
  var result = getNetworkData();//此网络请求堵塞了当前线程
  print('网络数据: $result');
  print('main end');

  */

  // main start
  // 网络数据: hell word
  // main end
//-------------------------------------------------------------------------

  //加入Future后

  /* var future = getNetworkData2(); //1、发送一个网络请求
  print('future = $future');
  //2.拿到结果
  //then后面的回调函数什么时候被执行？
  future.then((value) {
    print('value = $value');
  }).catchError((err) {
    print("打出错误：$err");
  }).whenComplete(() => {print("代码执行完成")});

  print('main end');*/

  /*
      main start
      future = Instance of 'Future<dynamic>'
      main end
      value = hell word
      代码执行完成

   */

  //--------------------------------------------------------------------------

  // print(' Future的链式调用');
/*
  Future((){
    //1.发送第一次请求
    sleep(Duration(seconds: 2));
    return '第一次的结果';
    
  }).then((value){
      print('第一次 value = $value');
    //2.发送的第二次请求
    sleep(Duration(seconds: 2));
    //return "第二次的结果";
    throw Exception('第二次请求异常');
    
  }).then((value){
    print('第二次 value = $value');
  }).catchError((err){
    print('err = $err');
  }).whenComplete(() => {
    print("代码完成")
  });

  print('main end');

  */

  /*
    main start
    main end
    第一次 value = 第一次的结果
    err = Exception: 第二次请求异常
    代码完成
   */

  //----------  await、async -------------------------------

  /*
  await、async是Dart中的关键字，他们可以让我们用同步的代码格式，去实现异步的调用过程。并且，通常一个async的函数会返回一个Future。使用await、async
  await、async相当于Future的语法糖
  1.await必须在async函数中才能使用
  2.async函数返回的结果必须是一个Future

  await需要写在耗时操作之前，表示等待该操作结果

   */

  /* var result = getNetworkData3().then((value){
    print('getNetworkData3 返回结果：value = $value');
  });

  print('getNetworkData3 result = $result');
  print('main end');
*/
  //main start
  // getNetworkData3 result = Instance of 'Future<Null>'
  // main end
  // getNetworkData3 返回结果：value = Hello World

  //-------------   链式调用普通写法 --------------------

  // getData();
  // print('main end');

  //main start
  // main end
  // 返回一 value = Hello World argument1
  // 返回二 value = Hello World Hello World argument1
  // 返回三 value = Hello World Hello World Hello World argument1

//---------------   使用await、async进行链式调用  -----------------------------
  getData2().then((value) {
    print('最终结果$value');
  }).catchError((err) {
    print(err);
  });
  print('main end');

  /*
    main start
    main end
    Hello World async 进行链式调用 argument1
    Hello World Hello World async 进行链式调用 argument1
    Hello World Hello World Hello World async 进行链式调用 argument1
    最终结果Hello World Hello World Hello World async 进行链式调用 argument1
   */

}

String getNetworkData() {
  sleep(Duration(seconds: 2)); //堵塞当前线程
  return 'hell word';
}

//加入Future后
Future getNetworkData2() {
  return Future(() {
    //1.将耗时操作包裹到Future的回调函数中
    //1.1结果情况1:只要有返回结果，就执行Future对应的then的回调
    //1.2结果情况2:如果没有结果返回（有错误信息），需要在Future回调中抛出一个异常
    sleep(Duration(seconds: 2));
    //模拟结果情况1
    return 'hell word';
    //模拟结果情况2
    // throw Exception('我是错误信息');
  });
}

//添加指定返回类型
Future<int> getNetworkData22() {
  //添加指定返回类型
  return Future<int>(() {
    //1.将耗时操作包裹到Future的回调函数中
    //1.1结果情况1:只要有返回结果，就执行Future对应的then的回调
    //1.2结果情况2:如果没有结果返回（有错误信息），需要在Future回调中抛出一个异常
    sleep(Duration(seconds: 2));
    //模拟结果情况1
    return 1;
    //模拟结果情况2
    // throw Exception('我是错误信息');
  });
}

Future getNetworkData3() async {
  var response = await Future.delayed(
      const Duration(seconds: 1), () => "Hello World"); //这里写耗时操作
  // return response;
  return "Hello World";
}

Future getNetworkData4(String arg) {
  return Future(() {
    sleep(Duration(seconds: 2));
    return "Hello World " + arg;
  });
}

//链式调用普通写法
void getData() {
  //1.调用第一次网络请求
  getNetworkData4('argument1').then((value) {
    print('返回一 value = $value');
    return getNetworkData4(value);
  }).then((value) {
    print('返回二 value = $value');
    return getNetworkData4(value);
  }).then((value) {
    print('返回三 value = $value');
  });
}

//使用await、async进行链式调用
Future getData2() async {
  //1.调用第一次网络请求
  var res1 = await getNetworkData4('async 进行链式调用 argument1');
  print(res1);

  var res2 = await getNetworkData4(res1);
  print(res2);

  var res3 = await getNetworkData4(res2);
  print(res3);

  return res3;
}
